#include <sstream>
#include <ctime>
#include <memory>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <string>
#include <filesystem>
#include "Mutex.hpp"
namespace logModule
{
    using namespace mutexModule;
    // zdl:: 构建日志的信息 2. 刷新落盘(screen )
    const std::string defaultLogPath = "./log";
    const std::string defaultLogFileName = "log.txt";

    // zdl:: 日志的等级
    enum class logLevel
    {
        debug = 1,
        info,
        warning,
        error,
        fatal
    };
    // zdl:: 获取当前的时间
    std::string level2String(logLevel level)
    {
        switch (level)
        {
        case logLevel::debug:
            return "debug";
        case logLevel::error:
            return "error";
        case logLevel::info:
            return "info";
        case logLevel::fatal:
            return "fatal";
        case logLevel::warning:
            return "warning";
        default:
            return "Unkonwn";
        }
    }
    std::string currentTime()
    {
        auto time_stamp(::time(nullptr));
        tm curr;
        localtime_r(&time_stamp, &curr);

        char buffer[1024];
        snprintf(buffer, sizeof(buffer),
                 "%04d-%02d-%02d %02d:%02d:%02d", curr.tm_year + 1900, curr.tm_mon + 1, curr.tm_mday, curr.tm_hour, curr.tm_min, curr.tm_sec);

        return buffer;
    }
    // zdl:: 刷新策略
    class LogStrategy
    {
    public:
        virtual ~LogStrategy() = default;
        virtual void SyncLog(const std::string &message) = 0;
    };
    // zdl:: 控制台策略
    class ConsoleLogStrategy : public LogStrategy
    {
    public:
        ConsoleLogStrategy()
        {
        }
        ~ConsoleLogStrategy()
        {
        }
        void SyncLog(const std::string &message) override
        {
            LockGuard guard(_lock);
            std::cout << message << std::endl;
        }

    private:
        Mutex _lock;
    };

    // zdl:: 3.2 文件策略
    class FileLogStrategy : public LogStrategy
    {
        public:
        FileLogStrategy(const std::string &logPath = defaultLogPath,
                        const std::string &logName = defaultLogFileName)
            : _logPath(logPath), _logName(logName)
        {
            // zdl:: 这里可以添加文件打开的逻辑
            LockGuard lock(_lock);
            // 确认logpath 存在
            if (std::filesystem::exists(_logPath) == false)
            {
                // zdl:: 如果不存在就创建
                std::filesystem::create_directories(_logPath);
            }
            else
            {
                return;
            }
            try
            {
                std::filesystem::create_directories(_logPath);
            }
            catch (std::filesystem::filesystem_error &e)
            {
                std::cerr << "Error creating log directory: " << e.what() << std::endl;
            }
        }

        ~FileLogStrategy()
        {
        }
        void SyncLog(const std::string &message)
        {
            LockGuard guard(_lock);
            // 将日志写入文件
            std::string log = _logPath + "/" + _logName;
            std::ofstream out(log, std::ios::app); // 日志写入，一定是追加的
            if (!out.is_open())
            {
                std::cerr << "Open error log file: " << log << std::endl;
                return;
            }
            out << message << std::endl;
            out.close();
        }

    private:
        Mutex _lock; // 锁
        std::string _logPath = defaultLogPath;
        std::string _logName = defaultLogFileName;
    };

    // zdl:: 接下来就是创建 日志类
    // 构建日志字符串
    class Logger
    {
    private:
        std::shared_ptr<LogStrategy> _strategy; // 日志刷新的策略方式

    public:
        Logger(/* args */)
        {
            // zdl:: 这里我们默认采用 console的方式
            _strategy = std::make_shared<ConsoleLogStrategy>();
        }
        void enableConsoleLog()
        {
            _strategy = std::make_shared<ConsoleLogStrategy>();
        }
        void enableFileLog(const std::string &logPath = defaultLogPath,
                           const std::string &logName = defaultLogFileName)
        {
            _strategy = std::make_shared<FileLogStrategy>(logPath, logName);
        }
        ~Logger()
        {
        }
        
        // zdl:: 一条完整的日志信息
        class LogMessage
        {
        public:
            LogMessage(logLevel &loglevel, const std::string &filename,
                       int &line, Logger &logger)
                : _currtime(currentTime()), _level(loglevel),
                  _pid(::getpid()), _filename(filename),
                  _line(line), _logger(logger)
            {
                std::stringstream ssbuffer;
                ssbuffer << "[ " << _currtime << " ]" << 
                "[ " << level2String(_level) << "] " 
                << "[ " <<  _pid << " ]" 
                << "[ " << _filename << " ]"
                << "[ " << _line << " ] - ";

                // _loginfo = ssbuffer.c_str();
                _loginfo = ssbuffer.str();
            }
            template <class t>
            LogMessage& operator<<(const t &info)
            {
                std::stringstream ss;
                ss << info;
                _loginfo += ss.str();
                return *this;
            }
            ~LogMessage()
            {
                if (_logger._strategy)
                _logger._strategy->SyncLog(_loginfo);
            }

        private:
            std::string _currtime;
            logLevel _level;
            pid_t _pid;
            std::string _filename; // 源文件name
            uint32_t _line;        // 日志所在的行号
            Logger &_logger;        // 负责根据不同的策略进行刷新
            std::string _loginfo;  // 一条完整的日志记录
        };


        // zdl: 现在再· logger 的类里面增加一个操作函数
        // 现在就是完成了拷贝操作
        LogMessage operator()(logLevel level, const std::string &filename,
        int line)
        {
            return LogMessage(level, filename, line, *this);
        }
    };
    Logger logger;
    #define LOG(Level) logger(Level, __FILE__, __LINE__)
    #define ENABLE_CONSOLE_LOG() logger.enableConsoleLog()
    #define ENABLE_FILE_LOG() logger.enableFileLog()
}